package org.beetlframework.mvc;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.beetlframework.FrameworkConstant;
import org.beetlframework.annotation.mvc.Action;
import org.beetlframework.annotation.mvc.Controller;
import org.beetlframework.annotation.mvc.DELETE;
import org.beetlframework.annotation.mvc.PUT;
import org.beetlframework.core.ClassHelper;
import org.beetlframework.util.ArrayUtil;
import org.beetlframework.util.CollectionUtil;
import org.beetlframework.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;



/**
 * 初始化 Action映射关系
 *
 * @author 草原狼
 * @since 1.0
 */
public class ActionMapping {
	private static final Logger logger = LoggerFactory.getLogger(ActionMapping.class);
	/**
     * Action Map（HTTP 请求与 Action 方法的映射）
     */
    private static final Map<Requestor, Handler> actionMap = new LinkedHashMap<Requestor, Handler>();
    
    static {
    	// 获取基础包下所有带 Controller注解的类
        List<Class<?>> ctrlAnnotationClassList = ClassHelper.getClassListByAnnotation(Controller.class);
        // 获取基础包下所有带 Controller后缀名的类
        List<Class<?>> ctrlNameSuffixClassList = ClassHelper.getClassListByNameSuffix("Controller");
        // 获取所有 Controller 类
        @SuppressWarnings("unchecked")
		List<Class<?>> controllerClassList = (List<Class<?>>)CollectionUtils.union(ctrlAnnotationClassList, ctrlNameSuffixClassList);
        
        if (CollectionUtil.isNotEmpty(controllerClassList)) {
            // 定义两个 Action Map
            Map<Requestor, Handler> commonActionMap = new HashMap<Requestor, Handler>(); // 存放普通 Action Map
            Map<Requestor, Handler> regexpActionMap = new HashMap<Requestor, Handler>(); // 存放带有正则表达式的 Action Map
            // 遍历 Action 类
            for (Class<?> actionClass : controllerClassList) {
                // 获取并遍历该 Action 类中所有的方法
                Method[] actionMethods = actionClass.getDeclaredMethods();
                if (ArrayUtil.isNotEmpty(actionMethods)) {
                    for (Method actionMethod : actionMethods) {
                    	if(checkActionMap(actionMethod, commonActionMap, regexpActionMap)){
                    		String message = String.format("Action映射冲突:%s", actionMethod.getAnnotation(Action.class).value());
                    		throw new RuntimeException(message);
                    	}
                    	// 处理 Action 方法
                        handleActionMethod(actionClass, actionMethod, commonActionMap, regexpActionMap);
                    }
                }
            }
            // 初始化最终的 Action Map（将 Common 放在 Regexp 前面）
            actionMap.putAll(commonActionMap);
            actionMap.putAll(regexpActionMap);
            if(FrameworkConstant.DEV_MODE){
            	println(actionMap);
            }
            
        }
    }
    
    /**
     * 以日志形式打印action映射关系
     * @param actionMap
     */
    private static void println(Map<Requestor, Handler> actionMap){
    	logger.debug("=============action映射开始=================");
    	String msg = String.format("url           ==> 全类名.方法名()");
    	logger.debug(msg);
    	logger.debug("--------------------------------------------");				
    	Set<Requestor> set = actionMap.keySet();
    	for(Requestor k :set){    		
    		String message = String.format("@%s(%s) ==> %s.%s", k.getRequestMethod(),k.getRequestPath(),actionMap.get(k).getActionClass(),actionMap.get(k).getActionMethod().getName()+"()");
    		logger.debug(message);    		
    	}
    	logger.debug("=============action映射结束=================");
    }
    
    /**
     * 检查当前映射是否已经存在容器
     * @param actionMethod
     * @param commonActionMap
     * @param regexpActionMap
     */
    private static boolean checkActionMap(Method actionMethod,Map<Requestor, Handler> commonActionMap, Map<Requestor, Handler> regexpActionMap){
    	if(FrameworkConstant.DEV_MODE){
    		//如果为开发模式，则需要检查
    		String requestPath = actionMethod.getAnnotation(Action.class).value();
        	Set<Requestor> set = commonActionMap.keySet();
        	for(Requestor req :set){
        		if(req.getRequestPath().equalsIgnoreCase(requestPath)){
        			return true;
        		}
        	}        	
        	set = regexpActionMap.keySet();
        	for(Requestor req :set){
        		if(req.getRequestPath().equalsIgnoreCase(requestPath)){
        			return true;
        		}
        	}
    	}    	
    	return false;
    }
    private static void handleActionMethod(Class<?> actionClass, Method actionMethod, Map<Requestor, Handler> commonActionMap, Map<Requestor, Handler> regexpActionMap) {       
    	// 判断当前 Action 方法是否带有 对应的 注解
    	if (actionMethod.isAnnotationPresent(Action.class)) {
            String requestPath = actionMethod.getAnnotation(Action.class).value();
            putActionMap("Action", requestPath, actionClass, actionMethod, commonActionMap, regexpActionMap);
        }
    	/*
    	else if (actionMethod.isAnnotationPresent(GET.class)) {
            String requestPath = actionMethod.getAnnotation(GET.class).value();
            putActionMap("GET", requestPath, actionClass, actionMethod, commonActionMap, regexpActionMap);
        } else if (actionMethod.isAnnotationPresent(POST.class)) {
            String requestPath = actionMethod.getAnnotation(POST.class).value();
            putActionMap("POST", requestPath, actionClass, actionMethod, commonActionMap, regexpActionMap);
        } 
        */
        else if (actionMethod.isAnnotationPresent(PUT.class)) {
            String requestPath = actionMethod.getAnnotation(PUT.class).value();
            putActionMap("PUT", requestPath, actionClass, actionMethod, commonActionMap, regexpActionMap);
        } else if (actionMethod.isAnnotationPresent(DELETE.class)) {
            String requestPath = actionMethod.getAnnotation(DELETE.class).value();
            putActionMap("DELETE", requestPath, actionClass, actionMethod, commonActionMap, regexpActionMap);
        }
    }
    
    private static void putActionMap(String requestMethod, String requestPath, Class<?> actionClass, Method actionMethod, Map<Requestor, Handler> commonActionMap, Map<Requestor, Handler> regexpActionMap) {
        // 判断 Request Path 中是否带有占位符
        if (requestPath.matches(".+\\{\\w+\\}.*")) {
            // 将请求路径中的占位符 {\w+} 转换为正则表达式 (\\w+)
            requestPath = StringUtil.replaceAll(requestPath, "\\{\\w+\\}", "(\\\\w+)");
            // 将 Requestor 与 Handler 放入 Regexp Action Map 中
            regexpActionMap.put(new Requestor(requestMethod, requestPath), new Handler(actionClass, actionMethod));
        } else {
            // 将 Requestor 与 Handler 放入 Common Action Map 中
            commonActionMap.put(new Requestor(requestMethod, requestPath), new Handler(actionClass, actionMethod));
        }
    }
    
    /**
     * 获取 Action Map
     */
    public static Map<Requestor, Handler> getActionMap() {
        return actionMap;
    }
}
